package extend

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.kotlin.KotlinLogger
import org.apache.logging.log4j.kotlin.KotlinLogger.Companion.FQCN
import org.apache.logging.log4j.kotlin.logger
import java.io.ByteArrayOutputStream
import java.util.zip.Deflater
import java.util.zip.Inflater

inline fun <reified T> T?.printLog(msg: Any?) {
    logger.info(msg)
    println(msg)
}

inline fun <reified T> T?.printLog(msg: String?, appendLogMsg: Any?) {
    logger.info(msg + appendLogMsg)
    println(msg)
}

fun KotlinLogger.debug(msg: CharSequence?) {
    delegate.logIfEnabled(FQCN, Level.DEBUG, null, msg, null)
}

fun KotlinLogger.debug(msg: CharSequence?, t: Throwable?) {
    delegate.logIfEnabled(FQCN, Level.DEBUG, null, msg, t)
}

fun KotlinLogger.info(msg: CharSequence?) {
    delegate.logIfEnabled(FQCN, Level.INFO, null, msg, null)
}

fun KotlinLogger.info(msg: CharSequence?, t: Throwable?) {
    delegate.logIfEnabled(FQCN, Level.INFO, null, msg, t)
}

fun KotlinLogger.info(msg: Any?) {
    delegate.logIfEnabled(FQCN, Level.INFO, null, msg, null)
}

fun KotlinLogger.warn(msg: CharSequence?) {
    delegate.logIfEnabled(FQCN, Level.WARN, null, msg, null)
}

fun KotlinLogger.warn(msg: CharSequence?, t: Throwable?) {
    delegate.logIfEnabled(FQCN, Level.WARN, null, msg, t)
}

fun KotlinLogger.error(msg: CharSequence?) {
    delegate.logIfEnabled(FQCN, Level.ERROR, null, msg, null)
}

fun KotlinLogger.error(msg: CharSequence?, t: Throwable?) {
    delegate.logIfEnabled(FQCN, Level.ERROR, null, msg, t)
}

fun KotlinLogger.fatal(msg: CharSequence?) {
    delegate.logIfEnabled(FQCN, Level.FATAL, null, msg, null)
}

fun KotlinLogger.fatal(msg: CharSequence?, t: Throwable?) {
    delegate.logIfEnabled(FQCN, Level.FATAL, null, msg, t)
}


@OptIn(ExperimentalSerializationApi::class)
val JSON
    get() = Json {
        // 指定是否编码默认值。默认情况下，如果属性的值与其默认值相同，将不会包含在生成的JSON中。通过设置encodeDefaults为true，可以强制包含所有属性，无论其是否与默认值相同。
        encodeDefaults = false
        // 指定是否忽略未知的JSON字段。默认情况下，如果JSON中包含未知的字段，将会抛出异常。通过设置ignoreUnknownKeys为true，可以忽略未知的字段而不抛出异常。
        ignoreUnknownKeys = true
        // 指定是否宽松解析JSON。默认情况下，JSON解析器对于不符合严格JSON规范的输入会抛出异常。通过设置isLenient为true，可以允许一些非严格的JSON语法，如单引号括起的字符串、未引号包围的键等。
        isLenient = true
        // 指定是否允许使用复杂的键类型。默认情况下，JSON解析器只接受字符串作为键。通过设置allowStructuredMapKeys为true，可以允许使用复杂的键类型，如自定义对象作为键。
        allowStructuredMapKeys = false
        // 指定是否对生成的JSON进行格式化美化。默认情况下，生成的JSON是紧凑的，没有额外的空格和换行符。通过设置prettyPrint为true，可以生成格式化良好的JSON，便于阅读和调试。
        prettyPrint = false
        // 允许解析器接受 JSON 对象和数组中的尾随（结束）逗号，使输入类似 [1, 2, 3,] 有效。 不影响编码。 false 默认情况下。
        allowTrailingComma = true
    }

/**
 * 压缩
 */
fun ByteArray.deflate(): ByteArray {
    return Deflater().also { it.setInput(this); it.finish() }
        .let { deflate ->
            ByteArrayOutputStream(this.size).use {
                ByteArray(1024).let { buffer ->
                    while (!deflate.finished()) {
                        val count = deflate.deflate(buffer)
                        it.write(buffer, 0, count)
                    }
                    deflate.end()
                }
                it
            }.toByteArray()
        }
}

/**
 * 解压
 */
fun ByteArray.inflate(): ByteArray {
    return Inflater().also { it.setInput(this) }
        .let { inflate ->
            ByteArray(1024).let { buffer ->
                ByteArrayOutputStream(this.size).use {
                    while (!inflate.finished()) {
                        val count = inflate.inflate(buffer)
                        it.write(buffer, 0, count)
                    }
                    inflate.end()
                    it
                }.toByteArray()
            }
        }
}

/**
 * 当前对象是否不为null或者boolean值是true
 * 如果是null或false 将会返回null值 否则返回 block返回的值
 */
inline fun <T, R> T?.ok(block: T.() -> R): R? {
    return when {
        this == null -> null
        this is Boolean && this -> block()
        this is String && this.isNotEmpty() -> block()
        else -> block()
    }
}

/**
 * 与ok相反
 *
 */
@Suppress("UNCHECKED_CAST")
inline fun <T, R> T?.no(block: () -> R): R? {
    return when {
        this == null -> block()
        this is Boolean && !this -> block()
        this is String && this.isEmpty() -> block()
        else -> this as R
    }
}